---
title: StateProvider
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import CodeBlock from "@theme/CodeBlock";
import product from "!!raw-loader!/docs/providers/state_provider/product.dart";
import productListView from "!!raw-loader!/docs/providers/state_provider/product_list_view.dart";
import dropdown from "!!raw-loader!/docs/providers/state_provider/dropdown.dart";
import sortProvider from "!!raw-loader!/docs/providers/state_provider/sort_provider.dart";
import connectedDropdown from "!!raw-loader!/docs/providers/state_provider/connected_dropdown.dart";
import sortedProductProvider from "!!raw-loader!/docs/providers/state_provider/sorted_product_provider.dart";
import updateReadTwice from "!!raw-loader!/docs/providers/state_provider/update_read_twice.dart";
import updateReadOnce from "!!raw-loader!/docs/providers/state_provider/update_read_once.dart";
import { trimSnippet } from "../../../../../src/components/CodeSnippet";

`StateProvider` is a provider that exposes a way to modify its state.
It is a simplification of [StateNotifierProvider], designed to avoid
having to write a [StateNotifier] class for very simple use-cases.

`StateProvider` exists primarily to allow the modification of
**simple** variables by the User Interface.  
The state of a `StateProvider` is typically one of:

- an enum, such as a filter type
- a String, typically the raw content of a text field
- a boolean, for checkboxes
- a number, for pagination or age form fields

You should not use `StateProvider` if:

- your state needs validation logic
- your state is a complex object (such as a custom class, a list/map, ...)
- the logic for modifying your state is more advanced than a simple `count++`.

For more advanced cases, consider using [StateNotifierProvider] instead and
create a [StateNotifier] class.  
While the initial boilerplate will be a bit larger, having a custom
[StateNotifier] class is critical for the long-term maintainability of your
project – as it centralizes the business logic of your state in a single place.

## Usage example: Changing the filter type using a dropdown

A real-world use-case of `StateProvider` would be to manage the state of
simple form components like dropdowns/text fields/checkboxes.  
In particular, we will see how to use `StateProvider` to implement a dropdown
that allows changing how a list of products is sorted.

For the sake of simplicity, the list of products that we will obtain
will be built directly in the application and will be as follows:

<CodeBlock>{trimSnippet(product)}</CodeBlock>

In a real-world application, this list would typically be obtained using
[FutureProvider] by making a network request.

The User Interface could then show the list of products by doing:

<CodeBlock>{trimSnippet(productListView)}</CodeBlock>

Now that we're done with the base, we can add a dropdown, which will
allow filtering our products either by price or by name.  
For that, we will use [DropDownButton](https://api.flutter.dev/flutter/material/DropdownButton-class.html).

<CodeBlock>{trimSnippet(dropdown)}</CodeBlock>

Now that we have a dropdown, let's create a `StateProvider` and
synchronize the state of the dropdown with our provider.

First, let's create the `StateProvider`:

<CodeBlock>{trimSnippet(sortProvider)}</CodeBlock>

Then, we can connect this provider with our dropdown by doing:

<CodeBlock>{trimSnippet(connectedDropdown)}</CodeBlock>

With this, we should now be able to change the sort type.  
It has no impact on the list of products yet though! It's now time for the
final part: Updating our `productsProvider` to sort the list of products.

A key component of implementing this is to use [ref.watch], to have
our `productsProvider` obtain the sort type and recompute the list of
products whenever the sort type changes.

The implementation would be:

<CodeBlock>{trimSnippet(sortedProductProvider)}</CodeBlock>

That's all! This change is enough for the User Interface to automatically
re-render the list of products when the sort type changes.

Here is the complete example on Dartpad:

<iframe
  src="https://dartpad.dev/embed-flutter.html?gh_owner=rrousselGit&gh_repo=riverpod&gh_path=website%2Fdocs%2Fproviders%2Fstate_provider"
  style={{ border: 0, width: "100%", aspectRatio: "2/1.5" }}
></iframe>

## How to update the state based on the previous value without reading the provider twice

Sometimes, you want to update the state of a `StateProvider` based on the previous value.
Naturally, you may end-up writing:

<CodeBlock>{trimSnippet(updateReadTwice)}</CodeBlock>

While there's nothing particularly wrong with this snippet, the syntax is a bit inconvenient.

To make the syntax a bit better, we can use the `update` function.
This function will take a callback that will receive the current state and is expected
to return the new state.  
We can use it to refactor our previous code to:

<CodeBlock>{trimSnippet(updateReadOnce)}</CodeBlock>

This change achieves the same effect while making the syntax a bit better.

[ref.watch]: ../concepts/reading#using-refwatch-to-observe-a-provider
[ref.read]: ../concepts/reading#using-refread-to-obtain-the-state-of-a-provider-once
[statenotifierprovider]: ./state_notifier_provider
[futureprovider]: ./future_provider
[statenotifier]: https://pub.dev/documentation/state_notifier/latest/state_notifier/StateNotifier-class.html
[provider]: ./provider
[asyncvalue]: https://pub.dev/documentation/riverpod/latest/riverpod/AsyncValue-class.html
[future]: https://api.dart.dev/dart-async/Future-class.html
[family]: ../concepts/modifiers/family
